package com.mlnx.ecg.ui.analysis;

import com.mlnx.ecg.ui.EcgAnalysis;
import com.mlnx.ecg.ui.analysis.config.AnalysisConfig;
import com.mlnx.ecg.ui.analysis.filter.ECG_STOP_FILTER;
import com.mlnx.ecg.ui.analysis.filter.EcgFilter;
import com.mlnx.ecg.ui.analysis.filter.FilterManager;
import com.mlnx.ecg.ui.analysis.jnalib.AnalysisLib;
import com.mlnx.ecg.ui.analysis.utils.FileUtils;
import com.mlnx.ecg.ui.config.ECGChannelType;
import com.mlnx.ecg.ui.model.HeartResult;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.ShortByReference;

import java.io.File;

/**
 * Created by amanda.shan on 2019/10/11.
 */
public class EcgAnalysisIml implements EcgAnalysis {

    private String deviceId;
    public byte[] gpu8AcId = new byte[]{0x0E, (byte) 0x80, 0x01, (byte) 0x80, 0x16, 0x51, 0x36, 0x32, 0x38,
            0x37, 0x37, 0x31};

    private EcgFilter ecgFilter;

    private AnalysisCallback analysisCallback;

//    private byte[] gpu8AcId = new byte[]{0x00, 0x00, 0x2F, 0x00, 0x16, 0x51, 0x36, 0x32, 0x38, 0x37, 0x37, 0x31};


    private AnalysisLib analysisLib;

    public EcgAnalysisIml(String deviceId, byte[] gpu8AcId) {
        this.deviceId = deviceId;
        this.gpu8AcId = gpu8AcId;
    }

//    public EcgAnalysisIml(String deviceId) {
//        this.deviceId = deviceId;
//    }
//
//    public EcgAnalysisIml(byte[] gpu8AcId) {
//        this.gpu8AcId = gpu8AcId;
//    }

    public AnalysisLib getAnalysisLib() {
        return analysisLib;
    }

    public void setAnalysisCallback(AnalysisCallback analysisCallback) {
        this.analysisCallback = analysisCallback;
    }

    @Override
    public void init() {
        String path = new File("ecg_analysis" + File.separator + "libecg12.dll").getAbsolutePath();

        path = getCopiedDllPath(path, deviceId);
        analysisLib = (AnalysisLib) Native.loadLibrary(path, AnalysisLib.class);
        initAnalysis();
    }

    private void initAnalysis() {
        // 算法初始化
        analysisLib.InitEcgAna();
        analysisLib.InitECGFilter();

        setEcgFilter(FilterManager.getSportEcgFilter());
    }

    @Override
    public void setEcgFilter(EcgFilter ecgFilter) {

        this.ecgFilter = ecgFilter;

        if (ecgFilter.getEcgStopFilter() == null) {
            ecgFilter.setEcgStopFilter(ECG_STOP_FILTER.ECG_STOP_FILTER_50);
        }

        analysisLib.SetFilter(ecgFilter.getLowPassFilter().getCode(), ecgFilter.getHighPassFilter().getCode()
                , ecgFilter.getEcgStopFilter().getCode());
    }


    //判断是否为约定的无效数据
    private boolean checkValid(ECGChannelType ecgChannelType, byte[] encryptionEcgDatas) {
        byte b = (byte) 0xFF;
        for (int i = 0; i < encryptionEcgDatas.length; i++) {
            if (encryptionEcgDatas[i] != b) {
                return true;
            } else {
                if (!ecgChannelType.equals(ECGChannelType.CHAN_8) && i == 8)
                    return false;
            }
        }

        return false;
    }

    @Override
    public byte[] realAnalysis(ECGChannelType ecgChannelType, byte[] encryptionEcgDatas, String deviceId) {

        int encryptionIndex = 0;

        int index = 0;

        if (encryptionEcgDatas != null && gpu8AcId != null) {
//            byte[] ecgData = new byte[encryptionEcgDatas.length];
            byte[] filterEcgData = new byte[6000];

            while (encryptionEcgDatas.length - encryptionIndex >= (ECGChannelType.CHAN_8.equals(ecgChannelType) ? 24 : 9)) {

                byte[] iEcgdata = new byte[24];
                //原始数据
                byte[] gu32EncryptEcgOutData = new byte[24];
                //滤波数据
                int[] filterData = new int[8];

                for (int i = 0; i < (ECGChannelType.CHAN_8.equals(ecgChannelType) ? 24 : 9); i++, encryptionIndex++) {
                    iEcgdata[i] = encryptionEcgDatas[encryptionIndex];
                }

                boolean valid = checkValid(ecgChannelType, iEcgdata);
                if (!valid) {
                    byte[] bytes = new byte[]{(byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X08, (byte) 0X08, (byte) 0X08, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F, (byte) 0X0F,};

                    for (int i = 0; i < gu32EncryptEcgOutData.length; i++, index++) {
                        filterEcgData[index] = bytes[i];
                    }

                    continue;
                }

                // 读取一行并解析数据
                analysisLib.GetProcData(iEcgdata, gpu8AcId, gu32EncryptEcgOutData);

                analysisLib.GetFilterData(filterData);

                // 判断是否可分析标志
                byte monitorFlag = analysisLib.CheckMonitorAnalysisStartFlag();

                if (monitorFlag == 1) {
                    // 调用分析函数
                    analysisLib.AlielseEcgAnalysis();
//                    System.out.println("  分析完成");

                    StringBuilder builder = new StringBuilder();

                    byte monitorResultFlag = analysisLib.MonitorAnalysisStopFlag();
                    if (monitorResultFlag == 1) {
                        // 获取结果
                        ShortByReference shortByReference = new ShortByReference();
                        analysisLib.EcgGetParam(0, shortByReference);
                        builder.append("心率：" + shortByReference.getValue() + " ");
                        if (shortByReference.getValue() >= 0) {
                            builder.append("转换后的心率：" + Math.round(shortByReference.getValue() * 1.028) + " ");
                            if (analysisCallback != null)
                                analysisCallback.renewHeart(deviceId,
                                        (int) Math.round(shortByReference.getValue() * 1.028));
                        }

                        analysisLib.EcgGetParam(1, shortByReference);
                        builder.append("早搏个数：" + shortByReference.getValue() + " ");
                        if (shortByReference.getValue() >= 0) {
                            // 早搏
//                            result.setPbNumb((int) shortByReference.getValue());
                        }

                        int[] sts = new int[8];
                        for (int i = 2, j = 0; i <= 9 && j < 8; i++, j++) {
                            analysisLib.EcgGetParam(i, shortByReference);
                            builder.append("st" + (j + 1) + "：" + shortByReference.getValue() + " ");
                            sts[j] = (int) shortByReference.getValue();
                        }
                        if (analysisCallback != null)
                            analysisCallback.renewSts(deviceId, sts);

                        IntByReference type = new IntByReference();
                        ShortByReference last_time = new ShortByReference();
                        ShortByReference currentPos = new ShortByReference();
                        analysisLib.EcgGetArrhythmia(type, last_time, currentPos);

                        if (analysisCallback != null)
                            analysisCallback.renewHeartResult(deviceId, HeartResult.decode(type.getValue()));


                        builder.append(" 疾病type:" + (type.getValue() & 0x7F)
                                + "--last_time:" + last_time.getValue()
                                + "--currentPos:" + currentPos.getValue());

                        // System.out.println("出结果:" + builder.toString());
                    }
                    analysisLib.ClearEcgAnalysisFlag();
                }

                if (getNewQrsFlag()) {
                    int rr = (int) (getNewRRWidth() * 4 / 1.028f);
                    clearNewQrsFlag();
//                    System.out.println("分析出RR：" + rr);
                }

                byte[] bytes = new byte[24];
                int j = 0;
                for (int i = 0; i < filterData.length; i++) {
                    bytes[j++] = (byte) (filterData[i] >> 16);
                    bytes[j++] = (byte) (filterData[i] >> 8);
                    bytes[j++] = (byte) (filterData[i]);
                }

                for (int i = 0; i < gu32EncryptEcgOutData.length; i++, index++) {
//                    ecgData[index] = gu32EncryptEcgOutData[i];
                    filterEcgData[index] = bytes[i];
                }
            }

            return filterEcgData;
        }
        return null;
    }

    // 获取检测是否得到实时最新的QRS波
    private boolean getNewQrsFlag() {
        byte flag = analysisLib.GetNewQrsFlag();
        return flag == 1 ? true : false;
    }

    // 获取RR间期结果
    private Integer getNewRRWidth() {
        IntByReference rr = new IntByReference();
        analysisLib.GetNewRRWidth(rr);

        return rr.getValue();
    }

    // 清除R波检测标志
    private void clearNewQrsFlag() {
        analysisLib.ClearNewQrsFlag();
    }


    private String getCopiedDllPath(String dllPath, String deviceId) {
        File currDirectory = new File("");
        File dll = new File(dllPath);
        File tempDirectory = new File(currDirectory.getAbsoluteFile()
                + File.separator + "temp");
        if (!tempDirectory.exists()) {
            tempDirectory.mkdir();
        }

        File tempDll = new File(tempDirectory.getAbsoluteFile()
                + File.separator + deviceId + AnalysisConfig.DLLSUFFIX);

        if (tempDll.exists()) {
            tempDll.delete();
        }

        if (!tempDll.exists()) {
            FileUtils.copyFile(dll, tempDll);
        }

        return tempDll.getAbsolutePath().replace(".dll", "");
    }

    // 设置心率计算导联
    @Override
    public void setBpmCalcLead(byte channel) {
        analysisLib.SetEcgChannel(channel);
    }
}
